package com.creative.core.controller;

import cn.hutool.captcha.*;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.creative.core.domain.AjaxResult;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import static com.creative.constant.Constants.EMAIL_CODE;
import static com.creative.constant.Constants.USER_CODE;
import static com.creative.core.domain.AjaxResult.error;
import static com.creative.core.domain.AjaxResult.success;
import static com.creative.core.domain.VerifyRegex.EMAIL;

/**
 * 验证码控制器
 * 创建人: ling
 * 创建时间: 2024/11/14
 */
@RestController
@Validated
@RequestMapping(value = "/captcha")
public class CaptchaController {
    private static final Log logger = LogFactory.get();
    // 用于轮询的索引
    private int captchaTypeIndex = (int) (Math.random() * 10);

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 创建验证码
     *
     * @param response 响应
     * @author ling
     * @date 2024/11/14
     */
    @GetMapping
    public AjaxResult createCaptcha(HttpServletResponse response) throws IOException {

        AjaxResult ajax = AjaxResult.success();
//        生成验证码的的唯一id
        String chauid = IdUtil.simpleUUID();
        String code = "";
        AbstractCaptcha captcha = null; // 用于存储生成的验证码对象
        switch (captchaTypeIndex % 4) {
            case 0:
                LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(145, 40);
                code = lineCaptcha.getCode();
                captcha = lineCaptcha;
                break;
            case 1:
                CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(145, 40, 4, 30);
                code = circleCaptcha.getCode();
                captcha = circleCaptcha;
                break;
            case 2:
                ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(145, 40, 4, 4);
                code = shearCaptcha.getCode();
                captcha = shearCaptcha;
                break;
            case 3:
                GifCaptcha gifCaptcha = CaptchaUtil.createGifCaptcha(145, 40);
                code = gifCaptcha.getCode();
                captcha = gifCaptcha;
                break;
        }
        // 将验证码保存到 Redis
        System.out.println("验证码：" + code);
//
//        String redis_key = USER_CODE + token_sessionId;

        String redis_key = USER_CODE + chauid;
//        将验证码和唯一凭证保存到 Redis   key   score传递当前时间
        stringRedisTemplate.opsForValue().set(redis_key, code);
//       设置有效期   60s
        stringRedisTemplate.expire(redis_key, 60L, TimeUnit.SECONDS);

        // 设置响应内容类型
//        response.setContentType("image/png");

        //        将token信息传递给前端    将tokenInfo添加至响应头中
//        获取token信息  多余 satoken已经在响应头中添加了 set-cookies 这个键，其中包含了token凭证
//        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
//        logger.info("token凭证：" + tokenInfo.getTokenValue());
//
//        response.addHeader("token", tokenInfo.getTokenValue());

//        response.addHeader("uuid", chauid);

        // 将验证码图片写入响应流
//        captcha.write(response.getOutputStream());

        ajax.put("uuid", chauid)
                .put("img", captcha.getImageBase64());

        // 关闭流
//        response.getOutputStream().close();

        captchaTypeIndex++; // 更新索引

        return ajax;
    }

//    /**
//     * 发送电子邮件验证码                   Fail ！！！！！！！
//     *
//     * @author ling
//     * @date 2024/11/17
//     */
//    @PostMapping
//    public void sendEmailCode() {
//        logger.info("发送电子邮件验证码");
//        MailUtil.send("2755665462@qq.com", "测试", "邮件来自Hutool测试", false);
//    }

    // 邮件协议
    private static final String emailProtocol = "smtp";
    // 发件人的SMTP服务器地址（普通QQ邮箱）
    private static final String emailSMTPHost = "smtp.qq.com";
    // 端口
    private static final String emailPort = "465";
    // 发件人邮箱地址
    private static final String emailAccount = "2253373466@qq.com"; // 这个是普通QQ邮箱
    // 发件人邮箱授权码
    private static final String emailPassword = "jcwxzjztuomyeahj";
    //  验证码
    private static final String title = "验证码";


    /**
     * 发送电子邮件验证码
     *
     * @param email 目标邮件地址
     * @return boolean
     * @author ling
     * @date 2024/07/26 11:38
     */
    @PostMapping
    public AjaxResult sendEmail(@RequestBody String email) {

        //        判断邮箱地址是否为空
        if (StrUtil.isEmpty(email)) {
            logger.info("电子邮件地址为空");
            return error("电子邮件地址为空");
        }
//        @Pattern(regexp = EMAIL,message = "无效的电子邮件地址")
        logger.info("发送电子邮件验证码");

//      去掉 “”
        if (StrUtil.startWith(email, "{")) {
            JSONObject emailaddress = JSONUtil.parseObj(email);
            email = emailaddress.getStr("email");
        }
        if (StrUtil.startWith(email, "\"")) {
            email = email.substring(1, email.length() - 1);
        }

        logger.info("目标邮箱：" + email);
//      校验邮箱地址是否合法
        if (!ReUtil.isMatch(EMAIL, email)) {
            logger.info("无效的电子邮件地址");
            return error("无效的电子邮件地址");
        }
        ;
//        生成随机的验证码
        String code = RandomUtil.randomNumbers(6);

        String content = "【XX网盘】您的验证码为：" + code + "，请于1分钟内填写。如非本人操作，请忽略本短信";

        try {
            // 1. 创建参数配置, 用于连接邮件服务器的参数配置
            Properties props = new Properties();
            props.setProperty("mail.transport.protocol", emailProtocol); // 使用的协议（JavaMail规范要求）
            props.setProperty("mail.smtp.host", emailSMTPHost); // 指定smtp服务器地址
            props.setProperty("mail.smtp.port", emailPort); // 指定smtp端口号
            // 使用smtp身份验证
            props.setProperty("mail.smtp.auth", "true"); // 需要请求认证
            props.put("mail.smtp.ssl.enable", "true"); // 开启SSL
            props.put("mail.smtp.ssl.protocols", "TLSv1.2"); // 指定SSL版本
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            // 由于Properties默认不限制请求时间，可能会导致线程阻塞，所以指定请求时长
            props.setProperty("mail.smtp.connectiontimeout", "10000");// 与邮件服务器建立连接的时间限制
            props.setProperty("mail.smtp.timeout", "10000");// 邮件smtp读取的时间限制
            props.setProperty("mail.smtp.writetimeout", "10000");// 邮件内容上传的时间限制
            // 2. 根据配置创建会话对象, 用于和邮件服务器交互
            Session session = Session.getDefaultInstance(props);
            session.setDebug(false); // 设置为debug模式, 可以查看详细的发送log
            // 3. 创建邮件
            MimeMessage message = new MimeMessage(session);
            // 4. From: 发件人（昵称有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改昵称）
            message.setFrom(new InternetAddress(emailAccount, "棂123xi", "UTF-8"));
            // 5. To: 收件人（可以增加多个收件人、抄送、密送）
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(email, "端木星灵", "UTF-8"));
            // MimeMessage.RecipientType.TO: 发送 MimeMessage.RecipientType.CC：抄送 MimeMessage.RecipientType.BCC：密送
//            int size = emails.size();
//             单个目标邮箱还是多个
//            if (size == 1) {
//                String email = emails.iterator().next();
//                message.setRecipient(Message.RecipientType.TO, new InternetAddress(email, email, "UTF-8"));
//            } else {
//                InternetAddress[] addresses = new InternetAddress[emails.size()];
//                int i = 0;
//                for (String email : emails) {
//                    addresses[i++] = new InternetAddress(email, email, "UTF-8");
//                }
//                message.setRecipients(MimeMessage.RecipientType.TO, addresses);
//            }

            // 6. Subject: 邮件主题（标题有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改标题）
            message.setSubject(title, "UTF-8");
            // 7. Content: 邮件正文（可以使用html标签）（内容有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改发送内容）
            message.setContent(content, "text/html;charset=UTF-8");
            // 8. 设置发件时间
            message.setSentDate(new Date());
            // 9. 保存设置
            message.saveChanges();
            // 10. 根据 Session 获取邮件传输对象
            Transport transport = session.getTransport();
            transport.connect(emailAccount, emailPassword);
            // 11. 发送邮件, 发到所有的收件地址, message.getAllRecipients()获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人
            transport.sendMessage(message, message.getAllRecipients());
            // 12. 关闭传输连接
            transport.close();
            logger.info("发送邮件成功！");

//            将验证码存到redis中
            stringRedisTemplate.opsForValue().set(EMAIL_CODE + email, code, 1, TimeUnit.MINUTES);

            return success();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("发送邮件失败,系统错误！", e);
            return error(e.getMessage());
        }
    }

//    public static void main(String[] args) {
//        sendEmail("2755665462@qq.com");
//    }
}
